Checker Network Payment Protocol

Author: @Nikolas Haimerl

This document explores possible solutions to a payment protocol architecture for the checker network.

Problem Statement

The Checker Network is a decentralized system designed to perform metric verification through a collaborative network of participants, facilitating reliable and transparent metric checking across different subnets. For all participants to work by the Checker Network’s protocol, there needs to be an economic incentive to act honestly. One important economic incentive is the payment for checks performed by the checkers. The Checker Network Payment Protocol needs to enable these payments for all network participants.

1. Actors in the Checker Network (Requirements & Goals)

The payment protocol must be architected to accommodate the distinct operational constraints of various network participants, ensuring each actor can effectively interact with the system's economic infrastructure. We list the actors here, describe their role and list key requirements that have to be met by a payment protocol.

1.1 Checker Client

  • Primary Role: Actor who pays for the Checker network to conduct checks. Examples would be Filecoin Foundation, Walrus, Storacha,…
  • Key Requirements/Goals:
    • Specify the payload for metric checks
    • Define the specific metric to be verified
    • Determine the frequency of checks
    • Provide financial resources to fund the checking process
    • Have access to a decentralized payment mechanism
    • Must be able to monitor the progress of the checks
    • Information that has to be known to checker clients at the time of payment:
      • How much is the cost of running the checks
      • What is the estimate on how long it takes for the first checks to be run
    • Need to be refunded if the payment fails or the checks are rejected (i.e. the checks are rejected by the checker nodes and never performed)

1.2 Checkers

  • Primary Role: Execute metric checks and report results
  • Key Requirements/Goals:
    • Perform accurate and timely metric checks
    • Submit results back to the Checker Network
    • Receive compensation for successful and accurate checks
    • The resources that are consumed while running the checks need to be reflected in the rewards for performing the checks
    • The checkers have varying technical backgrounds, so the designed payout process needs to be straightforward and user-friendly for everyone, regardless of their technical expertise.

1.3 Checker Network Aggregation Layer

  • Primary Role: Coordinate, validate, and aggregate metric check results
  • Key Requirements/Goals:
    • Collect incoming measurements from multiple checkers
    • Validate the authenticity and accuracy of submitted results
    • Calculate rewards for individual checkers
    • Aggregate and synthesize metric check data
    • Ensure transparency and fairness in the verification process

1.4 Payment Settlement Layer

  • Primary Role: Accept, aggregate and distribute funds
  • Key Requirements/Goals:
    • Collect assets or intention of committing funds
    • Create verifiable proofs of committed or collected funds
    • Allocate and aggregate credits for checkers and debits for checker clients
    • Trigger asset flow

2. Payment Settlement Mechanism

The goal of the payment settlement mechanism is to allow the checker client to fund the checks, the checkers to receive payment for their checks, and the Checker Network to take a cut.

2.1 Requirements

  • Decentralized payment infrastructure: The payment infrastructure should not be centralized (exp. PayPal, SWIFT,…)
  • Accessible to all participants with uncensored internet access
  • Transparent and auditable transaction process: Transactions must be verifiable by any network participant at any time.
  • Mechanism to incentivize honest and reliable checking: The checker’s must be incentivized to perform the checks in accordance with the checker client’s requirements and expectations. The Checker Network must not rely on checkers acting honestly without there being a clear economic incentive for it.
  • Enable Checker Clients to fund metric checks: Checker Clients provide the cash flow to fund the checkers’ work and fund the Checker Network itself.
  • Provide a fair compensation system for Checkers: Checkers must not be discriminated against outside of existing incentivization mechanisms (Reputation scores,…)
  • Create economic incentives for reliable and accurate metric verification that reflect the checker’s resource input: The work done by the checkers and the resources necessary to perform them must be reflected in the incentivization mechanism.
  • Support settlements through a censorship-resistant payment layer: The payment layer that is used to reward checkers and accept payments for checks from checker clients must not be subject to censorship by any government or institution (Our checkers are distributed worldwide and whether checkers can receive payment or clients can make payments should not rely on the jurisdiction in which they operate in)

3. Out of Scope (Non - Goals)

  • Validation of checks
  • Constructing Payloads for conducting checks
  • Creating Checker Network subnets that plug into the Checker Network
  • Comprehensive reputation system design

Checker Network Interaction Diagram

https://lucid.app/lucidspark/59b8ad98-25d7-413a-ab37-8b043fcd9b82/edit?invitationId=inv_e44624df-4ed4-4593-8956-a970c3ecfc87

The chart above shows a depiction of the payment protocol interaction. This chapter seeks to give an overview of what processes and steps are involved in allowing a checker client to have some check run by a Checker.

Nomenclature

  • Checker node: A checker node, also sometimes referred to just ‘checker’, is a single node in the Checker Network that runs the Checker Network app (similar to Filestation for spark)
  • Checker Network Round: A checker network round, or simply ‘round’, refers to a time interval in which all necessary operations by network participants are performed to get to the next iteration of forming a metric datapoint (For Spark, this would be file retrievability score, i.e. rsr).
  • Check: A check is a single operation performed by a single checker node.
  • Job: A Job encompasses all operations (these can include multiple checks) that a checker node has to perform during a single round. In Spark this means that a job for a checker includes performing multiple checks for different CIDs and the returning of RSR scores for each of the providers that were tested.

  1. Request a price estimate

A checker client that wants to run some job starts the interaction with the Checker Network by acquiring an estimate on how much a given job will cost. Possible variations of this estimate include a cost for a given time interval, a certain number of jobs and the frequency of jobs. Ideally, the checker client only specifies the frequency and in what interval the checks should be run and trusts the Checker Network to choose an appropriate number of checker nodes and geolocation so that the results can be considered trustworthy and averaged out over geolocations.

  1. Commit required funds

The checker client now knows how much the jobs will cost to run. They will now have to commit these funds to the payment settlement layer. The purpose of this step is for the checker client to commit the appropriate funds for the jobs to be run. The payment settlement layer acts as a fiduciary for these funds. They will not be moved until the jobs that were paid for have been performed or the time interval in which these jobs should be performed has expired. Should the Checker Network fail to perform all jobs in the given interval, the funds will be marked for withdrawal by the checker client. Jobs will only be performed against sufficient funds that are not yet marked for withdrawals. The committing of funds may be done through a blockchain such as Ethereum or Solana. Another possibility is the use of hashed timelock contracts, as they are commonly used in the Bitcoin network. The outcome of this step is the commitment of funds and a verification method for this commitment (For example, a tx hash)

  1. Process request for running checks

The checker client has now acquired an estimate on how much the jobs they wish to have performed cost, and they have committed the required amount of funds to the payment settlement layer. During this step the checker client may be asked to provide proof of the commitment of funds or the Aggregation Layer performs a validation on the blockchain or service where the funds are committed on.

  1. Allocate job to the pool of jobs

The next step is to request the Aggregation Layer of the Checker Network to process these jobs, and if processing is successful, add them to the pool of jobs that can be run by the checkers. This pool is unstructured and does not have any ordering. It serves as an intermediate where all jobs are stored that are not yet attached with a reward and can thus not yet be marked ready to be picked up by a checker.

  1. Attach reward to the job

This step includes attaching a given job with a reward which represents the per job payment. This reward should be identical or very similar to the original price estimate given to the checker client. The outcome of this step is the pairing of a job and a corresponding reward. The jobs are then ordered in a priority queue. The underlying mechanism of prioritization may be random, rely on a time-based principal (i.e. LIFO) or depend on the reward.

  1. Checker requests a set of checks to be processed in the next round

A checker will request a set of checks to be performed in a given round of checks from the checker network. This process will happen at every round interval. The selection of checks to be performed in a given round is still unclear. Two directions can be chosen to make this selection. Either the checker network itself decides which checks will get into which round or the checker can make the decision which checks they would like to perform. While the former is easier to implement on a high level, if the check’s rewards should accurately resemble the resources required to make the checks then this will pose a challenge when accounting for different types of Checker Network subnets (subnet that implements how to run a check) that use different resources and the rewards need to account for different resource inputs for every subnet. The latter would allow for a more accurate pricing model as checkers can decide for themselves whether a check is economically feasible or not. A big challenge with this approach is that it is hard to estimate how much a check will cost in step 1 and it is hard to guarantee certain check requirements such as frequency of checks when checkers can decide themselves which check they want to perform.

  1. Request status of checks

This step runs in parallel to the checker allocation and checkers requesting and performing checks. It is a standalone service that simply creates a state of checks and gives information about whether certain checks have been performed. This is important for the checker client to verify whether their jobs have been performed, for checkers to see whether their jobs were accounted for and for the subsequent payment service to decide which payments to roll out.

  1. Request payout list

Also in parallel, the first service in the payment settlement layer continuously asks for a list of checkers that are eligible for payout distributions. This list can be retrieved from the job state service which keeps track of which job has been performed by who. The payment service then creates a list of payouts and forwards them to be aggregated.

  1. Aggregate payout lists

Gas costs and the number of micro transactions are the main reasons why there is a need for an aggregation of payout lists. This is a simple process where for a given time interval all payout lists are aggregated by the checker addresses and if a checker address has reached a certain threshold of rewards it is eligible for payout distributions.

  1. Update Payout state

In this last step, the smart contract in which the funds from the checker client are committed is updated to account for the transfer of funds from the checker client to eligible checker addresses. The funds in the smart contract for each of the checker addresses is increased while the checker client funds are decreased. After this step, a checker can claim the funds and trigger, for example, an ETH payout or ERC20 transaction, which then moves the funds to whatever address a checker wants the payouts to be sent to.

Services

There currently are two services or subnets which require a higher degree of novelty compared to the existing spark protocol due to the Checker Network allowing for multiple different networks to be checked. These are the Checker Network Price Service and the Allocation Service. They are dependent on each other, and design decisions on one of them will need a subsequent change in the other service’s design.

The first section will discuss what a pricing service could look like.

Checker Price Service

There are several general directions to consider when designing the pricing service.

  • Iterative Protocol implementation: The protocol that determines the pricing model of the checker network should be implemented iteratively, meaning that we want an MVP as soon as possible that implements the basic functionality necessary for the Checker Network to work. It should also leave room for upgrading the protocol to a more advanced, complex and sustainable mechanism later on.
  • Price determinism: In the mechanism that determines the price of check, two different forces can influence the price. The first comes from the individual checkers, which have the most direct insight into what the break-even point for running a single check is given the resources that they have to use to perform the check. If the pricing mechanism were to rely only on the input of the checkers, then each checker could select which job they want to run based on the reward that is attached to that job and the resources that a checker estimates it is going to have to use to perform the job. The second force that has an impact on the price is the Checker Network itself. Similar to how the Spark protocol determines the price of its jobs, the price for each job in the Checker Network can be stipulated by the Checker Network directly. If this second force on the price was to be the only component that determines the price then this would mean that the Checker Network would need to make a good estimate in how many resources are going to be used for a job. This can become tricky if more and more networks are going to be checked and independent contributors want to add their network to the list of networks being checked.
  • Growth incentive: There is a point to be made about how much the Checker Network should subsidize check prices in the beginning stages of the network to boost adoption. Similar to how most networks need to bootstrap their network adoption in the beginning, the Checker Network could rely on subsidizing prices or altogether setting them to 0 to keep the barrier of entry as low as possible. Several strategies can be implemented here. Setting the price to 0 would mean that the Checker Network fully paid for jobs for as long as the underlying market dynamics are offset by these subsidies. This could mean that for a given period, a checker client that adds a new network to the Checker Network to allow for jobs being performed for that network can use the Checker Network for free. This, of course, highly depends on how much funds are available for bootstrapping the network.

Given these considerations, the design of a pricing service can be simplified by sacrificing accuracy of direct market dynamics and it can be increased in complexity to better resemble to the true price of a job. True price in this context means the marginal cost of performing another job.

It should also be said that the risk of not pricing the jobs accurately from the perspective of checkers is that checkers may opt out of performing checks and the Checker Network, thus losing participants in the Network. This is not necessarily an issue as long as the number of checkers that do perform a certain check is high enough and the checkers are geographically distributed enough. How much is enough is not part of this discussion.

The unique selling point of the Checker Network is that it allows for independent checks of certain metrics from nodes in a network that is distributed globally and has a sufficient number of nodes to allow for statistical certainties. Therefore, the price should reflect these two (possibly more) conditions, and the pricing algorithm should always strive to converge towards these conditions. To make it simple, the first draft of a pricing mechanism will only focus on preserving the desired number of checkers for a type of check.

A proposed algorithm that accounts for this behavior could look like the following.

https://lucid.app/lucidchart/5139e226-eed8-493c-8cb4-ab0d603eff7a/edit?beaconFlowId=CFED2815BDF7C35F&invitationId=inv_589a9b44-16b5-47c3-83f1-94ae5cc85bd8&page=0_0#

The algorithm proceeds as follows.

  1. As the initial condition, we have the Checker Network with CC number of checkers in the system. There exist multiple different Checker Network subnets with each testing a different network. The number of different Checker Network subnets is MM. For every one of those subnets mm there exists at least one Checker Client that wants to have checks performed using that subnet. For simplicity we assume that for every Checker Network subnets there exists exactly one Checker Client and they want to have NmN_m number of checks being performed for a given subnet mm. That means that the pricing service should try to find a reward rir_i for each check cic_i so that the number of checkers AmA_m  who are willing to perform check cic_i for subnet mm given reward rir_i  converges towards NmN_m. Let’s also assume that each Checker Client wants to have their subnet mm tested every round.
  1. During initialization the number MM needs to be computed. Also the number of checkers CC active in the coming round needs to be determined.
  1. In the next step all checks which should be performed in the upcoming round should be determined. In total they should amount to MCM*C number of checks. Every checker performs exactly one check per subnet.
  1. A reward function R(ci)=riR(c_i) = r_i computes the reward for a given check cic_i. This reward function is subject to an iterative updating process. Each round it is updated so that the reward in the next round will most likely result in a reward that leads to the desired number of checks NmN_m per subnet mm. Now there exist tuple of (ci,ri)(c_i,r_i) which defines a certain check and the reward that is expected to be received upon performing the check successfully.
  1. Now each checker is allocated their subset of checks. The checkers do have the option of opting out of checking certain subnets. This is necessary for checkers to be able to influence the reward function RR and thus apply the dynamics of supply and demand. If a certain number of checkers choose to opt out of checking a certain subnet (arguably for economic reasons as the given reward rir_i no longer covers the cost of the associated required resources) that means that the actual number of total checks performed for a subnet mm will no longer be MCM*C. AjmA^m_j represents whether checker jj performed the check for subnet mm in a given round. This means that Ajm=1Ajm=0A^m_j = 1 || A^m_j =0 . The total number of checks performed for a subnet mm in this round is then jCAjm=Sm\displaystyle\sum^C_{j}{A^m_j} = S_m.
  1. In the proceeding step SmS_m needs to be computed, and it can then be compared to NmN_m.

    There are three possibilities:

    • Sm<NmS_m < N_m: This means that the reward function RR needs to be updated to increase the rewards rir_i for a given subnet mm
    • Sm>NmS_m > N_m: In this case the reward function RR needs to be updated to decrease the rewards rir_i. There are more checkers than requested from the checker client checking the network metric for subnet mm. Thus, there is no economic incentive for more than NmN_m number of checkers to perform the check. To keep the price of the checks competitive the rewards rir_i  need to be reduced.
    • If both values are the same then there is no update that needs to be done to the reward function RR.

Market Mechanism

A key component of the pricing mechanism is the free market influence. Checker nodes have the opportunity to opt in or out of checking a certain subnet. This acts as feedback to the pricing mechanism to lower or raise the rewards for a given job.

  • Target number of checker nodes: For a certain subnet, there is a desired number of checkers who should be opted into checking this subnet as long as the subnet exists/there are requests for checks for this subnet. Should the actual number of checker nodes who have opted in or out of testing a given subnet be different to this desired number of opted-in checker nodes, then this will lead to a change in the rewards.
  • Reward inclusion: It is up to the subnet whether all checker nodes should be involved in checking the subnet in a given round or if only a subset of them is selected to perform the checks. Rewards are awarded to any checker node that successfully performs a job in a given round. A randomized subsampling of checker nodes to perform the checks will lead to an expected return for checker nodes over time. They may not be rewarded every round, but they can be certain that over time, their received rewards will converge towards the expected rewards.
  • Cold start: When a checker client wants to have a new subnet checked then there exist no prior market data to determine the fair price for the checks. There are a few ways how this challenge can be mitigated.
    • Estimate rewards: Based on the reward distributions of the other subnets we can take an educated guess on how checks for a new subnet should be priced. This is a simple solution that could get us off the ground at first, however with a more diverse set of subnets this becomes less feasible.
    • Boost rewards: A new subnet means uncertainty for checker nodes on whether the checks they perform will be rewarded accurately given the resource input. To make the adoption of new subnets more attractive for checkers, we could boost the rewards for a period of time until market dynamics generate enough datapoints to allow for a more accurate pricing.
  • Checker Client price estimate: A checker client wants to have as accurate as possible on how much a request for checking a subnet will cost. The rewards are constantly subject to change due to the iterative change of the reward function. This means that it is impossible to give a precise number on how much it will cost to check a subnet with certain requirements. Similar to how the gas fees and estimated time of inclusion of a transaction in a block in Ethereum or Bitcoin is estimated at the time when the user creates a transaction, we will likely have to give an estimate as well and also offer a maximum price, which should not be exceeded by the reward function. A checker client is primarily interested in two requirements.
    • Check Frequency: How often per time interval is a subnet checked
    • Check Duration: Until what timestamp will the Checker Network check a given subnet with the required frequency

    With this, we have three input factors for a checker client: frequency, duration and price.
    We could implement a slider or toggle that allows a checker client to control two of the three factors, and the third one will be adjusted based on the other two. For example, if a checker client wants a certain frequency and duration, the interface that the checker client interacts with proposes a certain price for the requested checks. Similarly, this can be done for any combination of two of these factors.

Visualization

A visualization of how the changes of the reward function looks like is shown below.

There are three charts in total. The simulation was done with 1000 checker nodes, a desired participation of 300 checker nodes and a starting reward for the jobs performed of 0. Each checker was assigned a random cost per job. The chart at the bottom shows each checker node as a bar, and the height of the bar is the assigned cost per job. This simulates different checkers having different costs associated with running the jobs. Each round, the iterative process looks at the target participation rate and the actual rate and makes an adjustment to the reward based on whether the target was over or under shot. Each round, the checkers will see whether the reward for a job is meeting their cost of running the job. If it covers the costs, then they will opt in; they will opt out if it does not cover it. The only fixed target is the number of checker nodes participating in checking a subnet. The reward which leads to this desired outcome is calculated iteratively.

Starting with the top chart. You can see the reward as it changes throughout the rounds. In the beginning it will slowly start picking up pace only to slow down once it gets close to the desired number of checker nodes that have opted in to check the subnet. It converges towards a reward of roughly 12. Note that this reward is an outcome of the simulation NOT a predetermined value set before running the simulation.

The second chart shows the participation of checker nodes throughout the rounds. You can see that it stays 0 until the first checker node opts in due to the reward being higher than its associated cost. After that, more and more checker nodes follow as their costs are also covered as the reward keeps increasing. Once the target number of checker nodes (300 in the case of the simulation) gets close, the rate of checkers joining the subnet goes down, and the number of checker nodes opting in converges towards 300.

The third chart was already explained partially. The red line shows the optimal reward given the cost structure of the checker nodes. You can see that roughly a third (300/1000) of the checker nodes’ cost is below the red line, while the rest is above. This is the desired outcome, as 2/3rds of the checker nodes are discouraged from joining the network.

The reward update function used was:
ri+1=ri[1+sign(PTPC)(a(PTPC)/PT)]r_{i+1} = r_i*[1+sign(P_T-P_C)*(a*|(P_T-P_C)/P_T|)]

where PTP_T is the target participation number and PCP_C  is the current participation number. aa is a fixed adoption rate which can be changed to increase or decrease the speed at which the reward curve converges. rir_i is the reward for running a job in round ii.

The proposed design covers the following aspects:

  • Incentivize the Checker Network to keep the number of checkers that perform checks for a given subnet as close as possible to the target number that was requested from the client
  • Checkers can influence the rewards by opting in or out of checking a given subnet. This way, the rewards resemble more closely the underlying resources used to perform the checks.
  • The design of the price service allows for subsidies or free trials for checker clients
  • Checker clients can decide how many checks they want to target for their subnet. This means that each the result of those checks always needs to be looked at in relation to the number of checks performed. There should be a recommended minimum number of checks, which could be set as the default.
  • The reward function can be selected to fit the needs of the protocol. The covering to the desired number of checks for a given subnet can be done faster and more aggressive (which comes with bigger swings in reward changes) or a slower and less aggressive (which makes for a more steady and controlled reward change) are possible.
  • The Checker Network can draw up a list of checks to be performed. This makes it easier to meet the requirements of the checker clients, such as frequency and number of checks performed.
  • Cold starts of subnets are covered by creating extra incentives to cover those checks, which offset the risk associated with performing new checks where resource use is not yet known.

Considerations

Here, the considerations when designing the Checker Price Service are listed.

  • A direct market pricing dynamic. Checkers can select each check in a priority queue based on the rewards that each check gives. This design opens up a few issues, making it much harder to guarantee clients’ requirements and making it harder to predict pricing.
  • The Checker Network stipulates all rewards. In this design, the Checker Network tries to estimate the resource use for each check. Adding new subnets is hard this way because there would need to be an assessment of all resources used during that test.
  • A direct market pricing dynamic with various factors that influence pricing based on the time a check has been in the queue awaiting being picked up or infrequently performed checks which require a higher frequency. This results in quite complex reward functions quickly and makes the design much more complex with little impact.

Attack Vectors

  • Reward dumping: An adversary could intentionally take jobs that are below their cost of running it to dump the reward, forcing honest nodes to out out. This attack is successful if the adversary runs enough nodes to meaningfully influence the reward function. This is the case if, for example, the desired number of opted-in checker nodes is 5000 and the adversary is running more than 2500 nodes. This would mean that the reward will be decreased as long as there are more than 5000 checker nodes opted into the subnet. In the end, this will mean that 2500 nodes are from the adversary, and 2500 nodes are honest. This goes to show that it is important to choose the number of desired checker nodes carefully.